home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / programm.ing / ams__l~1.zoo / src / blockmap.cc next >
Encoding:
C/C++ Source or Header  |  1993-09-07  |  8.5 KB  |  411 lines

  1. //////////////////////////////////////////////////////////////////////////////
  2. //
  3. //  This file is part of the Atari Machine Specific Library,
  4. //  and is Copyright 1992 by Warwick W. Allison.
  5. //
  6. //  You are free to copy and modify these sources, provided you acknowledge
  7. //  the origin by retaining this notice, and adhere to the conditions
  8. //  described in the file COPYING.
  9. //
  10. //////////////////////////////////////////////////////////////////////////////
  11.  
  12. #include "BlockMap.h"
  13. #include "DoubleBuffer.h"
  14. #include <bool.h>
  15.  
  16. // If more than this fraction of changes are made, the whole
  17. // image is updated, on the premise that it is faster to draw the
  18. // blocks consecutively.
  19. #define OPTIMALMAXCHANGERATIO 5/6
  20.  
  21. int CeilingLog2(int x)
  22. // result-1 < logbase2(x) <= result
  23. {
  24.     int result=0;
  25.     while (x > (1<<result)) result++;
  26.     return result;
  27. }
  28.  
  29. BlockMap::BlockMap(short w, short h, short *map) :
  30.     use_short_not_char(TRUE),
  31.     dynamic(0),
  32.     width(w),
  33.     height(h),
  34.     shiftheight(CeilingLog2(w)),
  35.     views(0),
  36.     data(map)
  37. {
  38. }
  39.  
  40. BlockMap::BlockMap(short w, short h, char *map) :
  41.     use_short_not_char(FALSE),
  42.     dynamic(0),
  43.     width(w),
  44.     height(h),
  45.     shiftheight(CeilingLog2(w)),
  46.     views(0),
  47.     data((short*)map)
  48. {
  49. }
  50.  
  51. BlockMap::BlockMap(short w, short h, int MaxBlock=256) :
  52.     use_short_not_char(MaxBlock > 256),
  53.     dynamic(1),
  54.     width(w),
  55.     height(h),
  56.     shiftheight(CeilingLog2(w)),
  57.     views(0),
  58.     data(use_short_not_char
  59.         ? (new short[w<<shiftheight])
  60.         : ((short*) new char[w<<shiftheight]))
  61. {
  62. }
  63.  
  64. BlockMap::~BlockMap()
  65. {
  66.     if (dynamic) delete data;
  67. }
  68.  
  69. void BlockMap::Set(short x, short y, short ch)
  70. {
  71.     if (use_short_not_char)
  72.         data[(x<<shiftheight)+y]=ch;
  73.     else
  74.         ((char*)data)[(x<<shiftheight)+y]=ch;
  75.  
  76.     if (views) views->Touch(x,y);
  77. }
  78.  
  79.  
  80. int BlockMap::fput(FILE *fp)
  81. {
  82.     return 0;
  83. }
  84.  
  85. int BlockMap::fget(FILE *fp)
  86. {
  87.     return 0;
  88. }
  89.  
  90. short BlockMap::operator() (short x, short y)
  91. {
  92.     return use_short_not_char
  93.             ? data[(x<<shiftheight)+y]
  94.             : ((char*)data)[(x<<shiftheight)+y];
  95. }
  96.  
  97. BlockMapView::BlockMapView(BlockMap& m, BlockImages& Im, short sx, short sy, short w, short h, short x=0, short y=0) :
  98.     map(&m), images(&Im),
  99.     maxchanges(w*h*OPTIMALMAXCHANGERATIO), next(map->views),
  100.     x(x),y(y)
  101. {
  102.     map->views=this;
  103.     change[0]=new ChangeList[maxchanges];
  104.     change[1]=new ChangeList[maxchanges];
  105.     views(x,y);
  106.     MoveView(sx,sy);
  107.     Resize(w,h);
  108. }
  109.  
  110. void BlockMapView::MoveView(short sx, short sy)
  111. {
  112.     pageoffset=(sy * Pages->Current().Rez().BytesPerLine() / 2)
  113.             + (sx / 16 * Pages->Current().Rez().BitPlanes());
  114. }
  115.  
  116. void BlockMapView::Draw()
  117. {
  118.     short nc=changes[Pages->Pulse];
  119.  
  120.     if (!nc) return; // Short circuit for most common case.
  121.  
  122.     short *Line=(short*)Pages->Location()+pageoffset;
  123.     int LineSpacing=Pages->Current().Rez().BytesPerLine()/2;
  124.  
  125.     if (map->use_short_not_char) {
  126.         // THIS CODE IS IDENTICAL TO OTHER if BRANCH EXCEPT FOR THIS LINE
  127.         short *D=map->data+(x<<map->shiftheight)+y;
  128.  
  129.         if (1 || nc > maxchanges) {
  130.             for (short i=0; i<width; i++) {
  131.                 short *To=Line;
  132.                 for (short j=0; j<height; j++) {
  133.                     images->Draw(D[j],To,LineSpacing);
  134.                 }
  135.                 D+=1<<map->shiftheight;
  136.                 Line+=images->wordwidth;
  137.             }
  138.         } else {
  139.             int BlockSpacing=LineSpacing*images->height;
  140.             int DD=1<<map->shiftheight;
  141.             ChangeList *C=change[Pages->Pulse];
  142.             for (short c=0; c<nc; c++) {
  143.                 short *To=Line+C[c].y*BlockSpacing+C[c].x*images->wordwidth;
  144.                 images->Draw((D+DD*C[c].x)[C[c].y],To,LineSpacing);
  145.             }
  146.         }
  147.     } else {
  148.         // THIS CODE IS IDENTICAL TO OTHER if BRANCH EXCEPT FOR THIS LINE
  149.         char *D=(char*)map->data+(x<<map->shiftheight)+y;
  150.  
  151.         if (1 || nc > maxchanges) {
  152.             for (short i=0; i<width; i++) {
  153.                 short *To=Line;
  154.                 for (short j=0; j<height; j++) {
  155.                     images->Draw(D[j],To,LineSpacing);
  156.                 }
  157.                 D+=1<<map->shiftheight;
  158.                 Line+=images->wordwidth;
  159.             }
  160.         } else {
  161.             int BlockSpacing=LineSpacing*images->height;
  162.             int DD=1<<map->shiftheight;
  163.             ChangeList *C=change[Pages->Pulse];
  164.             for (short c=0; c<nc; c++) {
  165.                 short *To=Line+C[c].y*BlockSpacing+C[c].x*images->wordwidth;
  166.                 images->Draw((D+DD*C[c].x)[C[c].y],To,LineSpacing);
  167.             }
  168.         }
  169.     }
  170.  
  171.     changes[Pages->Pulse]=0;
  172. }
  173.  
  174. void BlockMapView::TouchMe()
  175. {
  176.     changes[0]=maxchanges+1;
  177.     changes[1]=maxchanges+1;
  178. }
  179.  
  180. void BlockMapView::Touch()
  181. {
  182.     changes[0]=maxchanges+1;
  183.     changes[1]=maxchanges+1;
  184.     if (next) next->Touch();
  185. }
  186.  
  187. void BlockMapView::Touch(short x, short y)
  188. {
  189.     if (x>=x && y>=y && x<x+width && y<y+height) {
  190.         for (short c=0; c<2; c++) {
  191.             if (changes[c] < maxchanges) {
  192.                 change[c][changes[c]].x=x-x;
  193.                 change[c][changes[c]].y=y-y;
  194.                 changes[c]++;
  195.             } else {
  196.                 changes[c]=maxchanges+1;
  197.             }
  198.         }
  199.     }
  200.  
  201.     if (next) next->Touch(x,y);
  202. }
  203.  
  204. void BlockMapView::ViewsMap(BlockMap& m)
  205. {
  206.     if (&m != map) {
  207.         for (BlockMapView** cursor=&map->views;
  208.             *cursor!=this; cursor=&((*cursor)->next));
  209.         *cursor=(*cursor)->next;
  210.         map=&m;
  211.         next=map->views;
  212.         map->views=this;
  213.         TouchMe();
  214.     }
  215. }
  216.  
  217. BlockImages::BlockImages(short Blocks, short WordsPerBlock, short WWidth, short Height) :
  218.     wordwidth(WWidth), height(Height),
  219.     maxblocks(Blocks),
  220.     blockshift(CeilingLog2(WordsPerBlock)),
  221.     blockdata(new short[Blocks<<blockshift])
  222. {
  223. }
  224.  
  225.  
  226. BlockImages::~BlockImages()
  227. {
  228.     delete blockdata;
  229. }
  230.  
  231.  
  232. MonochromeBlockImages::MonochromeBlockImages(short Blocks,short Height)
  233.     : BlockImages(Blocks, Height, 1, Height)
  234. { }
  235.  
  236. void MonochromeBlockImages::Draw(short c, short*& At, int LineSpacing)
  237. {
  238. #ifdef NOASM
  239.     short *From=blockdata + ((int)c << blockshift);
  240.     short *tempAt=At;
  241.  
  242.     for (short i=height; i--;) {
  243.         *tempAt=*From++;
  244.         tempAt+=LineSpacing;
  245.     }
  246.  
  247.     At=tempAt;
  248. #else // Only 17% speed-up, but it's written now...
  249.     asm("
  250.         movel    %1@,a0
  251.         addl    %2,%2
  252.         subw    #1,%3
  253. 0:
  254.         movew    %0@+,a0@
  255.         addl    %2,a0
  256.         dbra    %3,0b
  257.  
  258.         movel    a0,%1@
  259.  
  260.     "    : // Outputs
  261.         : // Inputs
  262.             "a" (blockdata+((int)c << blockshift)),
  263.             "a" (&At),
  264.             "d" (LineSpacing),
  265.             "d" (height)
  266.         : "a0"
  267.     );
  268. #endif
  269. }
  270.  
  271. void MonochromeBlockImages::GetImage(short c, int x, int y, Screen& From)
  272. {
  273.     int LineSpacing=From.Rez().BytesPerLine()/2;
  274.     short *F=(short*)From.Location() + y*LineSpacing + x/16;
  275.     short *T=blockdata + ((int)c << blockshift);
  276.  
  277.     for (short i=height; i--;) {
  278.         *T++ = *F;
  279.         F+=LineSpacing;
  280.     }
  281. }
  282.  
  283. WideMonochromeBlockImages::WideMonochromeBlockImages(short Blocks,short Height)
  284.     : BlockImages(Blocks, Height*2, 2, Height)
  285. { }
  286.  
  287. void WideMonochromeBlockImages::Draw(short c, short*& At, int LineSpacing)
  288. {
  289.     long *From=(long*)(blockdata + ((int)c << blockshift));
  290.     long *tempAt=(long*)At;
  291.     LineSpacing/=2;
  292.  
  293.     for (short i=height; i--;) {
  294.         *tempAt=*From++;
  295.         tempAt+=LineSpacing;
  296.     }
  297.  
  298.     At=(short*)tempAt;
  299. }
  300.  
  301. void WideMonochromeBlockImages::GetImage(short c, int x, int y, Screen& From)
  302. {
  303.     int LineSpacing=From.Rez().BytesPerLine()/4;
  304.     long *F=(long*)((short*)From.Location() + x/16) + y*LineSpacing;
  305.     long *T=(long*)(blockdata + ((int)c << blockshift));
  306.  
  307.     for (short i=height; i--; ) {
  308.         *T++ = *F;
  309.         F+=LineSpacing;
  310.     }
  311. }
  312.  
  313.  
  314.  
  315. ColourBlockImages::ColourBlockImages(short Blocks,short Height)
  316.     : BlockImages(Blocks, Height*4, 4, Height)
  317. { }
  318.  
  319. void ColourBlockImages::Draw(short c, short*& At, int LineSpacing)
  320. {
  321.     long *From=(long*)(blockdata + ((int)c << blockshift));
  322.     long *tempAt=(long*)At;
  323.     LineSpacing/=2;
  324.     LineSpacing-=1;
  325.  
  326.     for (short i=height; i--;) {
  327.         *tempAt++=*From++;
  328.         *tempAt=*From++;
  329.         tempAt+=LineSpacing;
  330.     }
  331.  
  332.     At=(short*)tempAt;
  333. }
  334.  
  335. void ColourBlockImages::GetImage(short c, int x, int y, Screen& From)
  336. {
  337.     int LineSpacing=From.Rez().BytesPerLine()/2;
  338.     short *F=(short*)From.Location() + y*LineSpacing + x/16*4;
  339.     short *T=blockdata + ((int)c << blockshift);
  340.  
  341.     for (short i=height; i--;) {
  342.         *T++ = F[0];
  343.         *T++ = F[1];
  344.         *T++ = F[2];
  345.         *T++ = F[3];
  346.         F+=LineSpacing;
  347.     }
  348. }
  349.  
  350. WideColourBlockImages::WideColourBlockImages(short Blocks,short Height)
  351.     : BlockImages(Blocks, Height*8, 8, Height)
  352. { }
  353.  
  354. void WideColourBlockImages::Draw(short c, short*& At, int LineSpacing)
  355. {
  356.     long *From=(long*)(blockdata + ((int)c << blockshift));
  357.     long *tempAt=(long*)At;
  358.     LineSpacing/=2;
  359.     LineSpacing-=3;
  360.  
  361.     for (short i=height; i--;) {
  362.         *tempAt++=*From++;
  363.         *tempAt++=*From++;
  364.         *tempAt++=*From++;
  365.         *tempAt=*From++;
  366.         tempAt+=LineSpacing;
  367.     }
  368.  
  369.     At=(short*)tempAt;
  370. }
  371.  
  372. void WideColourBlockImages::GetImage(short c, int x, int y, Screen& From)
  373. {
  374.     int LineSpacing=From.Rez().BytesPerLine()/2;
  375.     short *F=(short*)From.Location() + y*LineSpacing + x/16*4;
  376.     short *T=blockdata + ((int)c << blockshift);
  377.  
  378.     for (short i=height; i--;) {
  379.         *T++ = F[0];
  380.         *T++ = F[1];
  381.         *T++ = F[2];
  382.         *T++ = F[3];
  383.         *T++ = F[4];
  384.         *T++ = F[5];
  385.         *T++ = F[6];
  386.         *T++ = F[7];
  387.         F+=LineSpacing;
  388.     }
  389. }
  390.  
  391. void BlockImages::GetImages(short c, short num, Screen& S)
  392. {
  393.     int x=0;
  394.     int y=0;
  395.     int xspacing=wordwidth*16/S.Rez().BitPlanes();
  396.     int swidth=S.Rez().Width();
  397.  
  398.     while (num) {
  399.         GetImage(c,x,y,S);
  400.  
  401.         x+=xspacing;
  402.         if (x>=swidth) {
  403.             x=0;
  404.             y+=height;
  405.         }
  406.  
  407.         num--;
  408.         c++;
  409.     }
  410. }
  411.